﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.Controllers;
using RainEngine.SceneManagement;
using Microsoft.Xna.Framework.Input;

namespace RainEngine.SceneNodes.UI
{
    /// <summary>
    /// 列表框
    /// </summary>
    public class UIListBox : UISceneNode
    {
        #region 成员变量和构造函数

        //默认值
        private static readonly Vector2  DefaultSize = new Vector2 (160,92);
        private static readonly Rectangle DefaultListboxRect = new Rectangle(1, 1, 6, 6);
        private static readonly float DefaultScrollBarWidth = 16.0f;
        private static readonly Rectangle  DefaultSelectionRect = new Rectangle (0, 24, 128, 16);

        /// <summary>
        /// 文字项数组
        /// </summary>
        private List<string> items = new List<string>(); 

        /// <summary>
        /// 列表框中可见的文字项数量，它是由列表框高度和文字项高度计算得出的
        /// </summary>
        int visibleItemsCount;        

        /// <summary>
        /// 列表框图像矩形
        /// </summary>
        Rectangle listboxRect;        

        /// <summary>
        /// 滚动条宽度，默认为16。高度无需指定，等于列表框高度。
        /// </summary>
        private float scrollBarWidth;

        /// <summary>
        /// 选择项的背景的目标矩形
        /// </summary>
        Rectangle selectionDestinationRect;

        /// <summary>
        /// 选择项的背景图像矩形
        /// </summary>
        Rectangle selectionRect;

        /// <summary>
        /// 鼠标所处的文字项索引，初始值为-1。
        /// </summary>
        int hoverIndex = -1;

        public int HoverIndex
        {
            get { return hoverIndex; }            
        }
        
        /// <summary>
        /// 选中的文字项的索引，初始值为-1，表示没有选中。
        /// </summary>
        int selectedIndex = -1;

        /// <summary>
        /// 选中的文字项的文字，默认为空字符。
        /// </summary>
        string selectedItem = string.Empty;

        /// <summary>
        /// 文字使用的字体
        /// </summary>
        protected SpriteFont font;

        /// <summary>
        /// 文字颜色
        /// </summary>
        protected Color fontColor;

        /// <summary>
        /// 竖直滚动条
        /// </summary>
        UIVScrollBar VScrollBar;        
        
        /// <summary>
        /// 文字项选中时引发的事件
        /// </summary>
        public event EventHandler Select = null;

        /// <summary>
        /// 选中的文字项改变时引发的事件
        /// </summary>
        public event EventHandler ChangeSelection = null;        

        /// <summary>
        /// 创建一个默认列表框，不包含文字项
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="setScene">所属场景</param>
        public UIListBox(RainGE engine, Scene setScene)
            : this(engine, setScene, null )
        { }

        /// <summary>
        /// 创建一个列表框，需要指定包含的文字项
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="setScene">所属场景</param>
        /// <param name="setItems">文字项数组</param>
        public UIListBox(RainGE engine, Scene setScene, string[] setItems)
            : this(engine, setScene, "UIListBox", Vector2.Zero, DefaultSize,DefaultListboxRect , engine.DefaultFont, Color.White, setItems , DefaultScrollBarWidth, DefaultSelectionRect,true)
        { }

        /// <summary>
        /// 创建一个列表框，内部方法，只能在引擎内部调用。
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="setScene">所属场景</param>
        /// <param name="setTextureName">纹理文件名称</param>
        /// <param name="setPosition">2D屏幕位置</param>
        /// <param name="setSize">列表框大小</param>
        /// <param name="setFont">字体</param>
        /// <param name="setTextColor">文字颜色</param>
        /// <param name="setItems">文字项数组</param>
        /// <param name="setScrollBarWidth">竖直滚动条宽度</param>
        /// <param name="setSelectionRect">被选择的文字项背景图像矩形</param>
        internal UIListBox(RainGE engine, Scene setScene, string setTextureName, Vector2 setPosition, Vector2  setSize,Rectangle setListboxRect, SpriteFont setFont, Color setTextColor, string[] setItems, float setScrollBarWidth, Rectangle setSelectionRect,bool useResource)
            : base(engine, setScene, setPosition, setTextureName,useResource )
        {
            this.size = setSize;
            this.listboxRect = setListboxRect;
            this.font = setFont;
            this.fontColor = setTextColor;
            this.selectionRect = setSelectionRect;
            this.scrollBarWidth  = setScrollBarWidth;           
            
            if (setItems != null)
            {                
                for (int i = 0; i < setItems.Length; i++)
                    this.items.Add(setItems[i]);
            }

            VScrollBar = new UIVScrollBar(engine, setScene);
            VScrollBar.TabStop = false;        
            Scene.AddNode(VScrollBar);
            //绘制列表框
            Redraw();
        }

        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置列表框图像矩形
        /// </summary>
        public Rectangle ListboxRect
        {
            get { return listboxRect; }
            set { listboxRect = value; }
        }

        /// <summary>
        /// 获取或设置滚动条宽度，默认为16。高度无需指定，等于列表框高度。
        /// </summary>
        public float ScrollBarWidth
        {
            get { return scrollBarWidth; }
            set
            {
                scrollBarWidth = value;
                Redraw();
            }
        }

        /// <summary>
        /// 获取或设置选中文字项的文字
        /// </summary>
        public string SelectedItem
        {
            get
            {
                if (selectedIndex != -1)
                    return items[selectedIndex];
                else
                    return "null";
            }
            set
            {
                for (int i = 0; i < items.Count; i++)
                    if (items[i] == value)
                    {
                        selectedIndex = i;
                        break;
                    }
            }
        }

        /// <summary>
        /// 获取或设置文字项数组
        /// </summary>
        public List<string> Items
        {
            get { return items; }
            set
            {
                items = value;
            }
        }

        /// <summary>
        /// 获取或设置文字使用的字体，字体改变时需要重新绘制列表框
        /// </summary>
        public SpriteFont Font
        {
            get { return font; }
            set
            {
                font = value;
                Redraw();
            }
        }       
        

        /// <summary>
        /// 获取或设置文字的颜色
        /// </summary>
        public Color FontColor
        {
            get { return fontColor; }
            set { fontColor = value; }
        }

        /// <summary>
        /// 获取选中的文字项的索引
        /// </summary>
        public int SelectedIndex { get { return selectedIndex; } set { selectedIndex = value; } }

        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string this[int index]
        {
            get
            {
                if (index > items.Count)
                    return "null";
                return items[index];
            }
            set
            {
                if (index > items.Count)
                    return;
                items[index] = value;
            }
        }

        #endregion       

        public override void Update(GameTime gameTime)
        {

            //如果鼠标在控件内部，则计算当前所处的文字项索引
            if (isMouseInside)
            {
                hoverIndex = VScrollBar.Value + (int)Math.Floor((Input.MousePos.Y - Position.Y) / font.LineSpacing);
                if (hoverIndex >= System.Math.Min(items.Count, VScrollBar.Value + visibleItemsCount) || hoverIndex < VScrollBar.Value)
                    hoverIndex = -1;
            }
            //如果鼠标位于一个文字项之上并且点击鼠标左键
            if (hoverIndex != -1 && Input.MouseLeftButtonPressed)
            {
                //存储上一帧选中的文字项索引
                int previousIndex = selectedIndex;
                //将hoverIndex的值传递给selectedIndex
                selectedIndex = hoverIndex;
                //引发Select事件
                if (Select != null)
                    Select(items[selectedIndex], null);
                //如果改变了选中的文字项则引发ChangeSelection事件
                if (selectedIndex != previousIndex && ChangeSelection != null)
                    ChangeSelection(items[selectedIndex], null);
            }

            base.Update(gameTime);
        }

        public override int Draw(GameTime gameTime)
        {

            //获取图像淡入淡出的透明颜色
            alphaTextureColor = new Color(Color.R, Color.G, Color.B, Scene.TransitionAlpha);

            //绘制背景
            RainGE.SpriteBatch.Draw(texture, new Rectangle((int)Position.X, (int)(Position.Y), (int)size.X, (int)size.Y), listboxRect, alphaTextureColor, Rotation, Origin, SpriteEffect, LayerDepth);

            //则绘制文字项的高亮背景
            if (hoverIndex >= VScrollBar.Value && hoverIndex < System.Math.Min(items.Count, VScrollBar.Value + visibleItemsCount))
            {
                selectionDestinationRect.Y = (int)(Position.Y + font.LineSpacing * (hoverIndex - VScrollBar.Value));
                RainGE.SpriteBatch.Draw(texture, selectionDestinationRect, selectionRect, alphaTextureColor, Rotation, Origin, SpriteEffect, LayerDepth);
            }

            //绘制选中的文字项的高亮背景
            if (selectedIndex >= VScrollBar.Value && selectedIndex < System.Math.Min(items.Count, VScrollBar.Value + visibleItemsCount))
            {
                selectionDestinationRect.Y = (int)(Position.Y + font.LineSpacing * (selectedIndex - VScrollBar.Value));
                RainGE.SpriteBatch.Draw(texture, selectionDestinationRect, selectionRect, alphaTextureColor, Rotation, Origin, SpriteEffect, LayerDepth);
            }

            //绘制文字项
            if (items.Count > 0)
            {
                for (int i = VScrollBar.Value; i < System.Math.Min(items.Count, VScrollBar.Value + visibleItemsCount); i++)
                {
                    Vector2 textOffset = Vector2.Zero;
                    textOffset.X = Position.X;
                    textOffset.Y = Position.Y + (i - VScrollBar.Value) * font.LineSpacing;
                    RainGE.SpriteBatch.DrawString(font, items[i], textOffset, fontColor);
                }

            }

            return 1;
        }

        #region 处理文字项数组的公有方法

        /// <summary>
        /// 在文字项数组中添加一个数据项
        /// </summary>
        /// <param name="item">文字项</param>
        public void AddItem(string item)
        {
            //在文字项数组中添加给定文字
            items.Add(item);
            Redraw();            
        }

        /// <summary>
        /// 根据给定文字项文字移除一个文字项
        /// </summary>
        /// <param name="item">给定的文字项文字</param>
        public void Remove(string item)
        {
            //如果文字项数组中不包含给定的文字则返回
            if (!items.Contains(item))
                return;
            items.Remove(item);
            Redraw();            
        }

        /// <summary>
        /// 根据索引移除一个文字项
        /// </summary>
        /// <param name="index">文字项索引</param>
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= items.Count)
                return;
            items.RemoveAt(index);
            Redraw();            
        }

        /// <summary>
        /// 清除文字项数组
        /// </summary>
        public void Clear()
        {
            items.Clear();
            Redraw();            
        }

        #endregion

        #region 事件相关处理程序

        /// <summary>
        /// 重新绘制列表框
        /// </summary>
        private void Redraw()
        {
            //根据列表框高度计算列表框可见的文字项数量
            visibleItemsCount = (int)System.Math.Ceiling(size.Y / font.LineSpacing);    
            //重新设置列表框大小
            this.size = new Vector2(size.X, visibleItemsCount*font.LineSpacing);
            //重新设置竖直滚动条的相关属性
            VScrollBar.MaxStep = items.Count - visibleItemsCount;
            VScrollBar.Size = new Vector2(scrollBarWidth, size.Y);
            VScrollBar.Position = new Vector2(Position.X + size.X - scrollBarWidth, Position.Y);
            VScrollBar.LargeChange = visibleItemsCount;
            //重新设置高亮图像的目标矩形
            this.selectionDestinationRect = new Rectangle((int)Position.X, (int)Position.Y, VScrollBar.Visible?(int)(size.X - VScrollBar.Size.X):(int)size.X, font.LineSpacing);
        }

        /// <summary>
        /// 列表框位置变化时需要重新绘制
        /// </summary>
        protected override void OnLocationChanged()
        {
            Redraw();
            base.OnLocationChanged();
        }

        /// <summary>
        /// 列表框大小变化时需要重新绘制
        /// </summary>
        protected override void OnSizeChanged()
        {
            Redraw();
            base.OnSizeChanged();
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            VScrollBar.Visible = visible;
        }

        #endregion

        #region 单元测试

#if DEBUG
        
#endif
        #endregion
    }
       
}
